package com.xt.wikiperfumapi.config;

import com.alibaba.fastjson2.JSONObject;
import com.xt.wikiperfumapi.filter.JwtFilter;
import com.xt.wikiperfumapi.model.vo.RestBean;
import com.xt.wikiperfumapi.service.AuthUserDetailService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.io.IOException;

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Resource
    AuthUserDetailService authUserDetailService;
    @Resource
    JwtFilter jwtFilter;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(auth -> auth
                .requestMatchers(HttpMethod.GET, "/api/mail/auth/**").permitAll()//邮箱
                .requestMatchers("/api/userData/**").hasAnyAuthority("user","shop")//用户收藏香水
                .requestMatchers("/api/order/**").hasAnyAuthority("user","shop")//用户订单
                .requestMatchers("/api/upload/**").hasAnyAuthority("user","shop")//上传接口
                .requestMatchers("/api/perfume/comment/**").hasAnyAuthority("user","shop")
//                .requestMatchers("").hasAnyAuthority("user","shop")

                .requestMatchers("/api/auth/isShop").hasAuthority("shop")

                .anyRequest().permitAll());
        http.cors(cors -> cors.disable());
        http.csrf(csrf -> csrf.disable());
        http.logout(AbstractHttpConfigurer::disable);//取消默认登出页面的使用
        http.authenticationProvider(authenticationProvider());//将自己配置的PasswordEncoder放入SecurityFilterChain中
//        http.userDetailsService(authUserDetailService);
//        因为authenticationProvider接口已经配置了该UserDetailsService和PasswordEncoder
        http.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));//禁用session，因为我们已经使用了JWT
        http.httpBasic(AbstractHttpConfigurer::disable);//禁用httpBasic，因为我们传输数据用的是post，而且请求体是JSON
        http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);//将用户授权时用到的JWT校验过滤器
        http.exceptionHandling(except -> except.authenticationEntryPoint(this::ex));
        // 添加进SecurityFilterChain中，并放在UsernamePasswordAuthenticationFilter的前面
        return http.build();
    }

    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setPasswordEncoder(passwordEncoder());
        provider.setUserDetailsService(authUserDetailService);
        return provider;
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
        return configuration.getAuthenticationManager();
    }

    @Bean//PasswordEncoder的实现类为BCryptPasswordEncoder
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    private void failureHandler(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException {
        response.setCharacterEncoding("utf-8");
        response.getWriter().write(JSONObject.toJSONString(RestBean.failure(401, e.getMessage())));
    }

    private void ex(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException {
        response.setCharacterEncoding("utf-8");
        response.getWriter().write(JSONObject.toJSONString(RestBean.failure(403, e.getMessage())));
    }

}

